from functools import cache

from utils import TreeNode


class Solution:
    def largestBSTSubtree(self, root: TreeNode) -> int:
        @cache
        def f(root):
            if not root:
                return float('inf'), float('-inf'), True, 0, 0
            lmin, lmax, lisbst, lsize, l_max_bst_size = f(root.left)
            rmin, rmax, risbst, rsize, r_max_bst_size = f(root.right)
            isbst = lisbst and risbst and lmax < root.val < rmin
            size = lsize + rsize
            max_bst_size = size if isbst else max(l_max_bst_size, r_max_bst_size)
            return min(lmin, rmin, root.val), max(lmax, rmax, root.val), isbst, size, max_bst_size
        return f(root)[4]
